
#include "ps2_client_ms.h"
#include "config.h"
#include <Arduino.h>

void PS2_Client_MS::makeData() {
    // 到采样时间才准备数据

    if (!_PS2_MS_INFO.Enable) {
        return;
    }

    u_long t = millis();
    if (_PS2_MS_INFO.mode == 0x01 && t >= _PS2_MS_INFO.SamplingRateTime) {
        _PS2_MS_INFO.SamplingRateTime = t + _PS2_MS_INFO.SamplingRateMs;
    } else {
        return;
    }

    /*
    第 0 字节：包含了鼠标按键状态和坐标溢出信息。
        D7：Y 坐标的变化量超出－256~255 的范围时为 1，否则为 0。
        D6：X 坐标的变化量超出－256~255 的范围时为 1，否则为 0。
        D5：Y 坐标变化的符号位，1 表示负数，即鼠标向下移动。
        D4：X 坐标变化的符号位，1 表示负数，即鼠标向左移动。
        D3：恒为 1。
        D2：中键状态，1 表示中键按下，0 表示未按下。
        D1：右键状态，1 表示右键按下，0 表示未按下。
        D0：左键状态，1 表示左键按下，0 表示未按下。
    第 1 字节：表示 X 坐标变化量，与第 1 字节的 D4 组成 9 位符号数，负数表示鼠标向左移，正数表示向右移。
    第 2 字节：表示 Y 坐标变化量，与第 1 字节的 D5 组成 9 位符号数，负数表示鼠标向下移，正数表示向上移。
    第 3 字节：表示 Z 位移，是 2 的补码，用于表示滚轮自上次数据报告以来的位移，有效值的范围在 - 8 到 + 7。
    */
    bool changed = false;

    _PS2_MS_INFO.data[0] = 0x08; // 有一位一直是1
    _PS2_MS_INFO.data[1] = 0x00;
    _PS2_MS_INFO.data[2] = 0x00;
    _PS2_MS_INFO.data[3] = 0x00;

    // 左右位移
    _PS2_MS_INFO.data[1] = _PS2_MS_INFO.Position[0];
    if (_PS2_MS_INFO.Position[0] < 0) {
        changed = true;
        _PS2_MS_INFO.data[0] |= 0x10;
    } else if (_PS2_MS_INFO.Position[0] > 0) {
        changed = true;
    }

    // 上下位移
    _PS2_MS_INFO.data[2] = _PS2_MS_INFO.Position[1];
    if (_PS2_MS_INFO.Position[1] < 0) {
        changed = true;
        _PS2_MS_INFO.data[0] |= 0x20;

    } else if (_PS2_MS_INFO.Position[1] > 0) {
        changed = true;
    }

    if (changed && _PS2_MS_INFO.Scaling) {
        // 2:1 比例
        for (int i = 1; i < 3; i++) {
            switch (_PS2_MS_INFO.data[i]) {
            case 0:
            case 1:
            case 3:
                break;
            case 2:
                _PS2_MS_INFO.data[i] = 1;
                break;
            case 4:
                _PS2_MS_INFO.data[i] = 6;
                break;
            case 5:
                _PS2_MS_INFO.data[i] = 9;
                break;
            default:
                _PS2_MS_INFO.data[i] <<= 1;
                break;
            }
        }
    }

    // 滚轮
    if (_PS2_MS_INFO.Position[2]) {
        changed = true;
        if (_PS2_MS_INFO.devID == 0x04) {
            _PS2_MS_INFO.data[3] |= _PS2_MS_INFO.Position[2] & 0x0F;
        } else {
            _PS2_MS_INFO.data[3] = (uint8_t)_PS2_MS_INFO.Position[2];
        }
    }

    for (int i = 0; i < 5; i++) {
        if (_PS2_MS_INFO.KeyStatusTmp[i] != _PS2_MS_INFO.KeyStatus[i]) {
            changed = true;
        }
        switch (i) {
        case 0: // 鼠标左键
            if (_PS2_MS_INFO.KeyStatusTmp[i]) {
                _PS2_MS_INFO.data[0] |= 0x01;
            }
            break;
        case 1: // 鼠标右键
            if (_PS2_MS_INFO.KeyStatusTmp[i]) {
                _PS2_MS_INFO.data[0] |= 0x02;
            }
            break;
        case 2: // 鼠标中键
            if (_PS2_MS_INFO.KeyStatusTmp[i]) {
                _PS2_MS_INFO.data[0] |= 0x04;
            }
            break;
        case 3: // 鼠标键4
            if (_PS2_MS_INFO.KeyStatusTmp[i]) {
                _PS2_MS_INFO.data[3] |= 0x10;
            }
            break;
        case 4: // 鼠标键5
            if (_PS2_MS_INFO.KeyStatusTmp[i]) {
                _PS2_MS_INFO.data[3] |= 0x20;
            }
            break;
        }

        _PS2_MS_INFO.KeyStatus[i] = _PS2_MS_INFO.KeyStatusTmp[i];
    }
    if (_PS2_MS_INFO.mode == 0x01) {
        // stream模式时主动发送
        if (changed) {
            PS2_TXBuffer[PS2_TX_E++] = _PS2_MS_INFO.data[0];
            PS2_TXBuffer[PS2_TX_E++] = _PS2_MS_INFO.data[1];
            PS2_TXBuffer[PS2_TX_E++] = _PS2_MS_INFO.data[2];
            if (_PS2_MS_INFO.devID != 0x00) {
                PS2_TXBuffer[PS2_TX_E++] = _PS2_MS_INFO.data[3];
            }
            _PS2_MS_INFO.Position[0] = 0;
            _PS2_MS_INFO.Position[1] = 0;
            _PS2_MS_INFO.Position[2] = 0;
        }
    }
}

// 设备复位
void PS2_Client_MS::resetDevice() {

    // 初始化鼠标
    _PS2_MS_INFO.STATUS = 1;            // 0x0: 未初始化； 0x01: 可用
    _PS2_MS_INFO.Enable = 0;            // 0: 停止扫描  1: 使能
    _PS2_MS_INFO.devID = 0x00;          // 0x00: 标准PS/2(3键，无滚轮)  0x03:Intellimouse（3键，有滚轮） 0x04：Intellimouse扩展（5键，有滚轮）
    _PS2_MS_INFO.mode = 0x01;           // 模式：00:初始化  01：stream（有变化就发送） 02：remote（查询才发送） 03：wrap（会送字节）
    _PS2_MS_INFO.last_mode = 0x00;      // 模式： 前一模式状态
    _PS2_MS_INFO.SamplingRate[0] = 100; // 采样率
    _PS2_MS_INFO.SamplingRate[1] = 0;
    _PS2_MS_INFO.SamplingRate[2] = 0;
    _PS2_MS_INFO.SamplingRateMs = 1000 / _PS2_MS_INFO.SamplingRate[0];
    _PS2_MS_INFO.SamplingRateTime = 0;
    _PS2_MS_INFO.Resolution = 2; // 分辨率 (4点/mm)
    _PS2_MS_INFO.Scaling = 0;    // 缩放比例 (1:1)
    memset(_PS2_MS_INFO.Position, 0, sizeof(_PS2_MS_INFO.Position));
    memset(_PS2_MS_INFO.KeyStatus, 0, sizeof(_PS2_MS_INFO.KeyStatus));
    memset(_PS2_MS_INFO.KeyStatusTmp, 0, sizeof(_PS2_MS_INFO.KeyStatusTmp));

    PS2_TX_S = PS2_TX_E;             // 清空缓存——不发送
    PS2_TXBuffer[PS2_TX_E++] = 0xAA; // 复位成功
    PS2_TXBuffer[PS2_TX_E++] = 0x00;
}

/*******************************************************************************
 * Function Name  : ps2_readAndExec_MS
 * Description    : 接收和执行指令
 * Input          : None
 * Output         : None
 * Return         : None
 *******************************************************************************/
void PS2_Client_MS::readAndExec() {
    uint8_t s;
    uint8_t cmd;
    uint8_t para;
    uint8_t data;
    static int step = 0;
    static unsigned long delay = 0;

    if (step == 0) {
        // 接收到缓存
        s = readIntoBuffer();
        if (s == 2) {
            // 读取到错误数据
            sendByte(0xFE); // 请求重发
            return;
        } else if (s == 1) {
            cmd = PS2_RXBuffer;
        } else {
            return;
        }

        if (_PS2_MS_INFO.mode == 0x03) {
            // wrap模式下，回送字节
            switch (cmd) {
            case 0xFF: // 复位
            case 0xEC: // 从wrap模式返回前一模式
                break;
            default:
                sendByte(cmd);
                return;
            }
        }

        switch (cmd) {
        case 0xE8: // 设置分辨率
        case 0xF3: // 设置采样率
            // 双字节指令，第一周期只回送 0xFA
            sendByte(0xFA);

            // 读取第二字节
            while (1) {
                s = readIntoBuffer();
                if (s == 2) {
                    // 读取到错误数据
                    sendByte(0xFE); // 请求重发
                } else if (s == 1) {
                    para = PS2_RXBuffer;
                    break;
                }
            }
            break;
        }

        switch (cmd) {
        case 0xE6:          // 设置缩放比例为1:1
            sendByte(0xFA); // 回复
            _PS2_MS_INFO.Scaling = 0;
            break;
        case 0xE7:          // 设置缩放比例为2:1
            sendByte(0xFA); // 回复
            _PS2_MS_INFO.Scaling = 1;
            break;
        case 0xE8:          // 设置分辨率
            sendByte(0xFA); // 回复
            _PS2_MS_INFO.Resolution = para;
            break;
        case 0xE9:          // 获取状态
            sendByte(0xFA); // 回复
            data = 0;
            if (_PS2_MS_INFO.KeyStatus[0]) {
                // 左键
                data |= 0x04;
            }
            if (_PS2_MS_INFO.KeyStatus[0]) {
                // 右键
                data |= 0x01;
            }
            if (_PS2_MS_INFO.KeyStatus[0]) {
                // 中键
                data |= 0x02;
            }
            if (_PS2_MS_INFO.Scaling) {
                // 缩放比例
                data |= 0x10;
            }
            if (_PS2_MS_INFO.Enable) {
                // 使能
                data |= 0x20;
            }
            if (_PS2_MS_INFO.mode == 0x02) {
                // remote mode
                data |= 0x40;
            }
            // sendByte(data);
            // sendByte(_PS2_MS_INFO.Resolution);      // 分辨率
            // sendByte(_PS2_MS_INFO.SamplingRate[0]); // 采样率
            PS2_TX_S = PS2_TX_E; // 清空缓存——不发送
            PS2_TXBuffer[PS2_TX_E++] = data;
            PS2_TXBuffer[PS2_TX_E++] = _PS2_MS_INFO.Resolution;
            PS2_TXBuffer[PS2_TX_E++] = _PS2_MS_INFO.SamplingRate[0];

            break;
        case 0xEA:          // 进入stream模式
            sendByte(0xFA); // 回复
            _PS2_MS_INFO.mode = 0x01;
            break;
        case 0xEB:               // remote模式时，查询位移
            PS2_TX_S = PS2_TX_E; // 清空缓存
            PS2_TXBuffer[PS2_TX_E++] = _PS2_MS_INFO.data[0];
            PS2_TXBuffer[PS2_TX_E++] = _PS2_MS_INFO.data[1];
            PS2_TXBuffer[PS2_TX_E++] = _PS2_MS_INFO.data[2];
            if (_PS2_MS_INFO.devID != 0x00) {
                PS2_TXBuffer[PS2_TX_E++] = _PS2_MS_INFO.data[3];
            }
            _PS2_MS_INFO.Position[0] = 0;
            _PS2_MS_INFO.Position[1] = 0;
            _PS2_MS_INFO.Position[2] = 0;
            break;
        case 0xEC:          // 从wrap模式返回前一模式
            sendByte(0xFA); // 回复
            _PS2_MS_INFO.mode = _PS2_MS_INFO.last_mode;
            break;
        case 0xEE:          // 进入wrap模式
            sendByte(0xFA); // 回复
            _PS2_MS_INFO.last_mode = _PS2_MS_INFO.mode;
            _PS2_MS_INFO.mode = 0x03;
            break;
        case 0xF0:          // 进入remote模式
            sendByte(0xFA); // 回复
            _PS2_MS_INFO.last_mode = _PS2_MS_INFO.mode;
            _PS2_MS_INFO.mode = 0x01;
            break;
        case 0xF2: // 询问device id
            // 更改设备ID
            if (_PS2_MS_INFO.SamplingRate[0] == 80 && _PS2_MS_INFO.SamplingRate[1] == 200 && _PS2_MS_INFO.SamplingRate[2] == 200) {
                _PS2_MS_INFO.devID = 0x04;
            } else if (_PS2_MS_INFO.SamplingRate[0] == 80 && _PS2_MS_INFO.SamplingRate[1] == 100 && _PS2_MS_INFO.SamplingRate[2] == 200) {
                _PS2_MS_INFO.devID = 0x03;
            }
            // sendByte(_PS2_MS_INFO.devID);
            PS2_TX_S = PS2_TX_E; // 清空缓存——不发送
            PS2_TXBuffer[PS2_TX_E++] = 0xFA;
            PS2_TXBuffer[PS2_TX_E++] = _PS2_MS_INFO.devID;

            break;
        case 0xF3:          // 设置采样率
            sendByte(0xFA); // 回复
            switch (para) {
            case 10:
            case 20:
            case 40:
            case 60:
            case 80:
            case 100:
            case 200:
                _PS2_MS_INFO.SamplingRate[2] = _PS2_MS_INFO.SamplingRate[1];
                _PS2_MS_INFO.SamplingRate[1] = _PS2_MS_INFO.SamplingRate[0];
                _PS2_MS_INFO.SamplingRate[0] = para;
                _PS2_MS_INFO.SamplingRateMs = 1000 / _PS2_MS_INFO.SamplingRate[0];
                break;
            default:
                break;
            }
            break;
        case 0xF4: // 使能
            _PS2_MS_INFO.Enable = 1;
            sendByte(0xFA);      // 回复
            PS2_TX_S = PS2_TX_E; // 清空缓存——不发送
            break;
        case 0xF5: // 禁止
            _PS2_MS_INFO.Enable = 0;
            sendByte(0xFA);      // 回复
            PS2_TX_S = PS2_TX_E; // 清空缓存——不发送
            break;
        case 0xF6:               // 设置缺省
            sendByte(0xFA);      // 回复
            PS2_TX_S = PS2_TX_E; // 清空缓存——不发送

            _PS2_MS_INFO.SamplingRate[0] = 100; // 采样率
            _PS2_MS_INFO.SamplingRate[1] = 0;
            _PS2_MS_INFO.SamplingRate[2] = 0;
            _PS2_MS_INFO.SamplingRateMs = 1000 / _PS2_MS_INFO.SamplingRate[0];
            _PS2_MS_INFO.Resolution = 2; // 分辨率 (4点/mm)
            _PS2_MS_INFO.Scaling = 0;    // 缩放比例 (1:1)
            _PS2_MS_INFO.last_mode = 0x00;
            _PS2_MS_INFO.mode = 0x01; // 模式：00:初始化  01：stream（有变化就发送） 02：remote（查询才发送） 03：wrap（会送字节）
            break;

        case 0xFF:               // 复位
            sendByte(0xFA);      // 回复成功
            PS2_TX_S = PS2_TX_E; // 清空缓存——不发送
            delay = millis() + 300;
            step = 1;

            break;
        default:
            sendByte(0xFA); // 回复
            break;
        }
    } else if (step == 1) {
        if (millis() >= delay) {
            resetDevice();
            step = 0;
        }
    }
}

void PS2_Client_MS::setKey(int key, int status) {
    _PS2_MS_INFO.KeyStatusTmp[key] = status;
}

void PS2_Client_MS::nodifyPosition(int pos, int16_t value) {
    _PS2_MS_INFO.Position[pos] += value;
}